package com.gzc.just.play.last.war.sceneserver.gameobject.unit;

import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObjectCamp;
import com.gzc.just.play.last.war.sceneserver.gameobject.base.GameObjectType;
import com.gzc.just.play.last.war.sceneserver.gameobject.base.Vector3;
import com.gzc.just.play.last.war.sceneserver.attribute.AttributeType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;

import static org.junit.jupiter.api.Assertions.*;

/**
 * GameUnit 单元测试 - 测试 15 个测试用例
 * 覆盖生命值管理、伤害、死亡、复活、移动、目标设定等功能
 */
@DisplayName("GameUnit 单元测试")
class GameUnitTest {

    private TestGameUnit gameUnit;
    private TestGameUnit enemy;

    /**
     * 测试用的 GameUnit 实现类
     */
    static class TestGameUnit extends GameUnit {
        public TestGameUnit(long objectId, GameObjectType objectType, GameObjectCamp camp,
                           int maxHealth, int maxMana, double attack, double defense, double speed) {
            super(objectId, objectType, camp, maxHealth, maxMana, attack, defense, speed);
        }

        @Override
        protected void checkDeadState() {
            // 测试实现
        }
    }

    @BeforeEach
    void setUp() {
        gameUnit = new TestGameUnit(1, GameObjectType.HERO, GameObjectCamp.TEAM_1, 1000, 500, 100, 50, 100);
        enemy = new TestGameUnit(2, GameObjectType.HERO, GameObjectCamp.TEAM_2, 800, 400, 80, 40, 80);
        gameUnit.initialize();
        enemy.initialize();
    }

    // ========== 初始化与状态 ==========

    @Test
    @DisplayName("测试1: GameUnit 初始化")
    void testGameUnitInitialization() {
        assertEquals(1000, gameUnit.getCurrentHealth());
        assertEquals(1000, gameUnit.getMaxHealth());
        assertEquals(500, gameUnit.getCurrentMana());
        assertEquals(500, gameUnit.getMaxMana());
        assertTrue(gameUnit.isAlive());
        assertFalse(gameUnit.isDead());
    }

    @Test
    @DisplayName("测试2: 验证初始属性")
    void testInitialAttributes() {
        assertEquals(100, gameUnit.getAttack());
        assertEquals(50, gameUnit.getDefense());
        assertEquals(100, gameUnit.getSpeed());
        assertEquals(0.0, gameUnit.getCriticalRate());
        assertEquals(0, gameUnit.getKillCount());
        assertEquals(0, gameUnit.getDeathCount());
    }

    // ========== 生命值管理 ==========

    @Test
    @DisplayName("测试3: 受到伤害")
    void testTakeDamage() {
        gameUnit.takeDamage(100);
        assertEquals(950, gameUnit.getCurrentHealth());
    }

    @Test
    @DisplayName("测试4: 伤害承受统计")
    void testDamageReceived() {
        int beforeHealth = gameUnit.getCurrentHealth();
        gameUnit.takeDamage(100);
        assertTrue(gameUnit.getCurrentHealth() < beforeHealth);
    }

    @Test
    @DisplayName("测试5: 恢复生命值")
    void testRestoreHealth() {
        gameUnit.takeDamage(200);
        int healthAfterDamage = gameUnit.getCurrentHealth();
        gameUnit.restoreHealth(100);
        assertTrue(gameUnit.getCurrentHealth() >= healthAfterDamage);
    }

    @Test
    @DisplayName("测试6: 生命值不超过最大值")
    void testHealthNotExceedMax() {
        gameUnit.takeDamage(100);
        gameUnit.restoreHealth(5000);
        assertTrue(gameUnit.getCurrentHealth() <= gameUnit.getMaxHealth());
    }

    @Test
    @DisplayName("测试7: 死后无法恢复生命值")
    void testNoHealthRestoreWhenDead() {
        gameUnit.die();
        assertTrue(gameUnit.isDead());
        gameUnit.restoreHealth(500);
        assertTrue(gameUnit.isDead());
    }

    @Test
    @DisplayName("测试8: 伤害导致死亡")
    void testDeathByDamage() {
        gameUnit.takeDamage(2000);
        assertTrue(gameUnit.isDead());
        assertFalse(gameUnit.isAlive());
    }

    // ========== 魔力管理 ==========

    @Test
    @DisplayName("测试9: 恢复魔力值")
    void testRestoreMana() {
        int initialMana = gameUnit.getCurrentMana();
        gameUnit.setCurrentMana(200);
        gameUnit.restoreMana(100);
        assertTrue(gameUnit.getCurrentMana() > 200);
    }

    @Test
    @DisplayName("测试10: 魔力值不超过最大值")
    void testManaNotExceedMax() {
        gameUnit.setCurrentMana(450);
        gameUnit.restoreMana(500);
        assertTrue(gameUnit.getCurrentMana() <= gameUnit.getMaxMana());
    }

    @Test
    @DisplayName("测试11: 死后无法恢复魔力")
    void testNoManaRestoreWhenDead() {
        gameUnit.die();
        int manaBeforeRestore = gameUnit.getCurrentMana();
        gameUnit.restoreMana(100);
        assertEquals(manaBeforeRestore, gameUnit.getCurrentMana());
    }

    // ========== 死亡与复活 ==========

    @Test
    @DisplayName("测试12: 死亡")
    void testDeath() {
        gameUnit.die();
        assertTrue(gameUnit.isDead());
        assertFalse(gameUnit.isAlive());
        assertEquals(1, gameUnit.getDeathCount());
    }

    @Test
    @DisplayName("测试13: 复活")
    void testRevive() {
        gameUnit.die();
        assertTrue(gameUnit.isDead());
        gameUnit.revive(50);
        assertTrue(gameUnit.isAlive());
        assertFalse(gameUnit.isDead());
        assertEquals(500, gameUnit.getCurrentHealth());
    }

    @Test
    @DisplayName("测试14: 击杀统计")
    void testKillCount() {
        assertEquals(0, gameUnit.getKillCount());
        gameUnit.addKill(enemy);
        assertEquals(1, gameUnit.getKillCount());
    }

    // ========== 移动与目标 ==========

    @Test
    @DisplayName("测试15: 设置目标")
    void testSetTarget() {
        assertNull(gameUnit.getCurrentTarget());
        gameUnit.setTarget(enemy);
        assertEquals(enemy, gameUnit.getCurrentTarget());
        gameUnit.setTarget(null);
        assertNull(gameUnit.getCurrentTarget());
    }

    // ========== 属性访问 ==========

    @Test
    @DisplayName("测试扩展1: getAttribute 方法")
    void testGetAttribute() {
        assertEquals(100, gameUnit.getAttribute(AttributeType.ATTACK));
        assertEquals(50, gameUnit.getAttribute(AttributeType.DEFENSE));
        assertEquals(100, gameUnit.getAttribute(AttributeType.SPEED));
        assertEquals(1000, gameUnit.getAttribute(AttributeType.MAX_HEALTH));
        assertEquals(1000, gameUnit.getAttribute(AttributeType.CURRENT_HEALTH));
    }

    @Test
    @DisplayName("测试扩展2: modifyAttribute 方法")
    void testModifyAttribute() {
        gameUnit.modifyAttribute(AttributeType.ATTACK, 50);
        assertEquals(150, gameUnit.getAttack());
        
        gameUnit.modifyAttribute(AttributeType.DEFENSE, 20);
        assertEquals(70, gameUnit.getDefense());
    }

    @Test
    @DisplayName("测试扩展3: 属性下限保护")
    void testAttributeBoundary() {
        gameUnit.modifyAttribute(AttributeType.MAX_HEALTH, -1500);
        assertTrue(gameUnit.getMaxHealth() >= 1);
        
        gameUnit.modifyAttribute(AttributeType.CRITICAL_RATE, 0.5);
        assertTrue(gameUnit.getCriticalRate() <= 1.0);
    }

    @Test
    @DisplayName("测试扩展4: 负伤害处理")
    void testNegativeDamage() {
        // 负伤害被转换为0，但由于防御力计算，会造成最小1点伤害
        int beforeHealth = gameUnit.getCurrentHealth();
        gameUnit.takeDamage(-100);
        int afterHealth = gameUnit.getCurrentHealth();
        // 伤害最少为 Math.max(1, 0 - defense)
        assertTrue(afterHealth <= beforeHealth);
    }

    @Test
    @DisplayName("测试扩展5: 防御力抵消伤害")
    void testDefenseReducesDamage() {
        int baseDamage = 100;
        int beforeHealth = gameUnit.getCurrentHealth();
        gameUnit.takeDamage(baseDamage);
        int afterHealth = gameUnit.getCurrentHealth();
        assertTrue(afterHealth < beforeHealth);
    }

    @Test
    @DisplayName("测试扩展6: 多次伤害累积")
    void testMultipleDamageAccumulation() {
        int beforeHealth = gameUnit.getCurrentHealth();
        gameUnit.takeDamage(100);
        gameUnit.takeDamage(100);
        gameUnit.takeDamage(100);
        assertTrue(gameUnit.getCurrentHealth() < beforeHealth);
    }

    @Test
    @DisplayName("测试扩展7: 生命值精确管理")
    void testHealthPrecision() {
        gameUnit.takeDamage(333);
        int health = gameUnit.getCurrentHealth();
        gameUnit.restoreHealth(111);
        assertTrue(gameUnit.getCurrentHealth() > health);
    }

    @Test
    @DisplayName("测试扩展8: 复活生命值百分比")
    void testReviveWithPercentage() {
        gameUnit.die();
        gameUnit.revive(25);
        assertTrue(gameUnit.getCurrentHealth() > 0);
        assertTrue(gameUnit.isAlive());
    }

    @Test
    @DisplayName("测试扩展9: 复活至少恢复1血")
    void testReviveMinHealth() {
        gameUnit.die();
        gameUnit.revive(1);
        assertTrue(gameUnit.getCurrentHealth() > 0);
    }

    @Test
    @DisplayName("测试扩展10: 单位状态转换")
    void testUnitStateTransition() {
        assertTrue(gameUnit.isAlive());
        gameUnit.die();
        assertFalse(gameUnit.isAlive());
        assertTrue(gameUnit.isDead());
        gameUnit.revive(100);
        assertTrue(gameUnit.isAlive());
        assertFalse(gameUnit.isDead());
    }
}
